#include <QCodeEdit/qcodeedit.h>
#include <QCodeEdit/qeditor.h>
#include <QCodeEdit/qformatscheme.h>
#include <QCodeEdit/qlanguagefactory.h>
#include <QCodeEdit/qdocument.h>
#include <QCodeEdit/qpanel.h>
#include <QCodeEdit/qdocumentline.h>
#include <QCodeEdit/qlinemarkpanel.h>
#include <QCodeEdit/qlinemarksinfocenter.h>

#include <QFileDialog>
#include <QMessageBox>
#include <QSettings>
#include <QFont>
#include <QCloseEvent>

#include "asyeditor.h"
#include "settings.h"

AsyEditor::AsyEditor(QWidget *parent)
    :QMainWindow(parent)
{
    ui.setupUi(this);
    prevLabel=new QLabel(this);
    prevLabel->setAlignment(Qt::AlignCenter);
    ui.scrollArea->setWidget(prevLabel);

    m_codeedit=new QCodeEdit(this);
    ui.stackW->addWidget(m_codeedit->editor());
    ui.stackW->setCurrentWidget(m_codeedit->editor());
    m_format=new QFormatScheme("qxs/asy.qxf",this);
    QDocument::setDefaultFormatScheme(m_format);

    QLineMarksInfoCenter::instance()->loadMarkTypes("qxs/marks.qxm");
    m_language=new QLanguageFactory(m_format,this);
    m_language->addDefinitionPath("qxs");
    m_codeedit->addPanel("Line Number Panel",QCodeEdit::West,true)
        ->setShortcut(QKeySequence("F11"));
//    m_codeedit->addPanel("Line Mark Panel",QCodeEdit::West,true);

    connect(ui.actCopy,SIGNAL(triggered()),m_codeedit->editor(),SLOT(copy()));
    connect(ui.actCut,SIGNAL(triggered()),m_codeedit->editor(),SLOT(cut()));
    connect(ui.actPaste,SIGNAL(triggered()),m_codeedit->editor(),SLOT(paste()));
    connect(ui.actUndo,SIGNAL(triggered()),m_codeedit->editor(),SLOT(undo()));
    connect(ui.actRedo,SIGNAL(triggered()),m_codeedit->editor(),SLOT(redo()));
    connect(m_codeedit->editor(),SIGNAL(contentModified(bool)),this,SLOT(sltContentModified(bool)));

    lastPath=QDir::currentPath();

    proc=new AsyProcess(this);
    connect(proc,SIGNAL(finished(int)),this,SLOT(sltProcFinished(int)));
    connect(proc,SIGNAL(error(QString)),this,SLOT(sltProcError(QString)));

    scaleFactory=1.0;
    loadConfig();

    on_actNew_triggered();
}

AsyEditor::~AsyEditor()
{

}

void AsyEditor::on_actOpen_triggered()
{

	if(isModified())
		return;
	QString filename = QFileDialog::getOpenFileName(this, tr("Open"),
			lastPath, tr("asy file(*.asy)"));
	if (filename.isEmpty()) {
		return;
	}
	lastPath=QFileInfo(filename).path();
	m_language->setLanguage(m_codeedit->editor(), filename);
	m_codeedit->editor()->load(filename);
	setWindowTitle(tr("AsyEditor -%1").arg(QFileInfo(filename).fileName()));
}

void AsyEditor::on_actNew_triggered()
{
	if(isModified())
		return;
	m_codeedit->editor()->setFileName("");
	m_codeedit->editor()->setText("");
	setWindowTitle(tr("AsyEditor -untitled"));
	m_language->setLanguage(m_codeedit->editor(), "*.asy");
}

void AsyEditor::on_actSave_triggered()
{
	save();
}

void AsyEditor::on_actExit_triggered()
{
	if(isModified())
		return;
	close();
}


void AsyEditor::on_actSettings_triggered()
{
	Settings *setdia=new Settings(this);
	setdia->exec();
	delete setdia;

	loadConfig();
}

void AsyEditor::on_actPrev_triggered()
{
	if(isModified())
		return;
	QLineMarksInfoCenter::instance()->clear();
    needPreview=true;
	proc->transform(m_codeedit->editor()->fileName(),"tmp",AsyProcess::ASY2PNG);
	statusBar()->showMessage(tr("runing asy..."));
}

void AsyEditor::on_retButton_clicked()
{
    ui.stackW->setCurrentIndex(1);
}

void AsyEditor::on_scaleCombo_currentIndexChanged(int index)
{
    switch (index) {
        case 0:
            scaleFactory=0.25;
            break;
        case 1:
            scaleFactory=0.5;
            break;
        case 2:
            scaleFactory=1.0;
            break;
        case 3:
        	scaleFactory=1.5;
        	break;
        case 4:
            scaleFactory=2.0;
            break;
        case 5:{
        	qreal sx=static_cast<qreal>(ui.scrollArea->width())/static_cast<qreal>(pixmap.width());
        	qreal sy=static_cast<qreal>(ui.scrollArea->height())/static_cast<qreal>(pixmap.height());
        	scaleFactory=(sx<sy?sx:sy);
        	break;
        }
        default:
            ;
    }
    prevLabel->setPixmap(pixmap.scaled(scaleFactory*pixmap.size(),Qt::KeepAspectRatio,Qt::SmoothTransformation));
}

void AsyEditor::sltContentModified(bool y)
{
	QString fn=m_codeedit->editor()->fileName();
	if(fn.isEmpty())
		fn=tr("untitled");

	setWindowTitle(tr("AsyEditor -%1*").arg(QFileInfo(fn).fileName()));
}

void AsyEditor::save()
{
	QString fn=m_codeedit->editor()->fileName();
	if(fn.isEmpty()){
		fn = QFileDialog::getSaveFileName(this, tr("Save"),
				lastPath,
				tr("asy file (*.asy)"));
		if(fn.isEmpty())
			return;
	}
	lastPath=QFileInfo(fn).path();
	m_codeedit->editor()->save(fn);
	m_language->setLanguage(m_codeedit->editor(), fn);
	setWindowTitle(tr("AsyEditor -%1").arg(QFileInfo(fn).fileName()));
}

bool AsyEditor::isModified()
{
	if(m_codeedit->editor()->isContentModified()){
		int ret=QMessageBox::warning(this,tr("Warning"),
				tr("document has modified\n do you save it?"),
				QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel,
				QMessageBox::Yes);
		switch(ret){
		case QMessageBox::Yes:
			save();
		case QMessageBox::No:
			return false;
		default:
			return true;
		}
	}
	return false;
}

void AsyEditor::loadConfig()
{
	QSettings set;
	set.beginGroup("Editor");
	QFont font=set.value("Font",qApp->font()).value<QFont>();
	m_codeedit->editor()->document()->setFont(font);
    m_codeedit->editor()->setCodec(set.value("Codec","UTF-8").toString().toLatin1().constData());
	set.endGroup();
	proc->loadConfig();

}

void AsyEditor::sltProcFinished(int type)
{
//    if (success) {
//        if (needPreview) {
//            ui.stackW->setCurrentIndex(0);
//            pixmap.load("tmp.png");
//            prevLabel->setPixmap(pixmap.scaled(scaleFactory*pixmap.size(),Qt::KeepAspectRatio,Qt::SmoothTransformation));
//            statusBar()->clearMessage();
//        }
//
//    }else {
//    	QMessageBox::critical(this,tr("Error"),proc->readErrorInfo());
//    }
	switch(type){
	case AsyOk:
		statusBar()->showMessage(tr("running gs..."));
		break;
	case AsyFailed:{
		QDocumentLine line=m_codeedit->editor()->document()->line(proc->asyErrorLineNumber());
		line.addMark(2);
		statusBar()->showMessage(proc->asyErrorInfo());
		break;
	}
	case GsFailed:
		QMessageBox::critical(this,tr("gs Error"),proc->readErrorInfo());
		break;
	case GsOk:
        if (needPreview) {
            ui.stackW->setCurrentIndex(0);
            pixmap.load("tmp.png");
            prevLabel->setPixmap(pixmap.scaled(scaleFactory*pixmap.size(),Qt::KeepAspectRatio,Qt::SmoothTransformation));
            statusBar()->clearMessage();
        }
        break;
	default:
		QMessageBox::critical(this,tr("Error"),tr("don't support translation"));
	}
}

void AsyEditor::sltProcError(QString errinfo)
{
	statusBar()->showMessage(errinfo);
}


void AsyEditor::closeEvent(QCloseEvent *event)
{
	if(isModified())
		event->ignore();
	else
		event->accept();
}
